import 'package:flutter/cupertino.dart';
import 'package:xbaistack/api/base_api.dart';
import 'package:xbaistack/model/model.dart';
import 'package:xbaistack/model/pager.dart';
import 'package:xbaistack/model/result.dart';

import '../widget/state_view.dart';


typedef ModelFuture<T> = Future<T> Function();
typedef ModelBuilder<T> = Widget Function(T data);

class BaseService<M extends Model<M>, Api extends BaseApi<M>>
    extends ValueNotifier<bool> {
  final Api api;
  final bool showLoading;

  BaseService(this.api, {this.showLoading = true}) : super(false);

  /// 触发 ValueNotifier 数据变更
  /// 当 ValueNotifier value 变更时会触发 ValueListenableBuilder 进行刷新
  void refresh() => super.value = !value;

  /// 通过主键查询某数据详情
  Future<M> selectById(String id) => api.selectById(id);

  /// 查询所有数据列表
  Future<List<M>> selectList() => api.selectList();

  /// 查询分页数据列表
  Future<Pager<M>> selectPageList({
    required int page,
    int? size,
    Map<String, dynamic>? query,
  }) {
    return api.selectPageList(page: page, size: size, query: query);
  }

  /// 创建成功后触发数据联动刷新
  void create(M model) => api.create(model).then((res) => refresh());

  /// 更新成功后触发数据联动刷新
  void updateById(M model) => api.updateById(model).then((res) => refresh());

  /// 删除成功后触发数据联动刷新
  void deleteById(String id) => api.deleteById(id).then((res) => refresh());

  /// 联动数据刷新渲染的方法
  /// 一种简易的 MVVM 实现方式
  Widget render<T>({
    required ModelFuture<T> future,
    required ModelBuilder<T> builder,
  }) {
    return ValueListenableBuilder(
      valueListenable: this,
      builder: (ctx, data, widget) => FutureBuilder(
        future: future.call(), // 调用 ModelFuture 回调，以获取异步请求任务
        builder: (ctx, snapshot) {
          final state = snapshot.connectionState;

          // Loading
          if (state == ConnectionState.waiting) {
            return showLoading ? StatusView() : const SizedBox.shrink();
          }

          // Error
          if (snapshot.hasError) {
            final error = snapshot.error;
            return StatusView(
              status: Status.FAILED,
              message: error is Result ? error.message : error.toString(),
            );
          }

          // Success
          if (snapshot.hasData) {
            return builder.call(snapshot.data as T);
          }

          // Empty
          return StatusView(status: Status.EMPTY);
        },
      ),
    );
  }
}